package wxapp

import (
	"crypto/tls"
	"wxsdk/wxpay/core"
	"errors"
	. "wxsdk/wxpay"
	"wxsdk/wxpay/utils/mapstruct"
	"github.com/astaxie/beego"
)

// 特别注意： 特约服务商退款，证书用服务商的，不能用商户的!!!!!
type RefundRequest struct {
	Appid          string   `xml:"appid"`                     //微信分配的小程序ID
	MchId          string   `xml:"mch_id"`                    //微信支付分配的商户号
	SubAppid       string   `xml:"sub_appid,omitempty"`       //小程序的APPID,当前调起支付的小程序APPID(服务商特有参数)
	SubMchId       string   `xml:"sub_mch_id,omitempty"`      //微信支付分配的子商户号(服务商特有参数)
	NonceStr       string   `xml:"nonce_str"`                 //随机字符串
	Sign           string   `xml:"sign"`                      //签名
	SignType       string   `xml:"sign_type,omitempty"`       //签名类型
	TransactionId  string   `xml:"transaction_id,omitempty"`  //微信订单号
	OutTradeNo     string   `xml:"out_trade_no,omitempty"`    //商户订单号
	OutRefundNo    string   `xml:"out_refund_no"`             //商户退款单号
	TotalFee       string   `xml:"total_fee"`                 //订单金额
	RefundFee      string   `xml:"refund_fee"`                //退款金额
	RefundFeeType  string   `xml:"refund_fee_type,omitempty"` //货币种类
	RefundDesc     string   `xml:"refund_desc,omitempty"`     //退款原因
	RefundAccount  string   `xml:"refund_account,omitempty"`  //退款资金来源	
}

// 申请退款
type RefundResponse struct {
	BaseResponse `xml:",innerXml,omitempty"`
	TransactionId       string `xml:"transaction_id,omitempty"`        // 微信订单号
	OutTradeNo          string `xml:"out_trade_no,omitempty"`          // 商户订单号
	OutRefundNo         string `xml:"out_refund_no,omitempty"`         // 商户退款单号
	RefundId            string `xml:"refund_id,omitempty"`             // 微信退款单号
	RefundChannel       string `xml:"refund_channel,omitempty"`        // 退款渠道
	RefundFee           string `xml:"refund_fee,omitempty"`            // 退款金额
	SettlementRefundFee string `xml:"settlement_refund_fee,omitempty"` // 应结退款金额
	TotalFee            string `xml:"total_fee,omitempty"`             // 订单总金额
	SettlementTotalFee  string `xml:"settlement_total_fee,omitempty"`  // 应结订单金额
	FeeType             string `xml:"fee_type,omitempty"`            // 订单金额货币种类
	CashFee             string `xml:"cash_fee,omitempty"`            // 现金支付金额
	CashFeeType         string `xml:"cash_fee_type,omitempty"`         // 现金支付币种
	CashRefundFee       string `xml:"cash_refund_fee,omitempty"`     // 现金退款金额
	CouponRefundFee     string `xml:"coupon_refund_fee,omitempty"`   // 代金券或立减优惠退款金额
	CouponRefundCount   string `xml:"coupon_refund_count,omitempty"` // 代金券或立减优惠使用数量
	/*
	CouponTypeN         string `xml:"coupon_type_$n,omitempty"`       //代金券类型
	CouponRefundIdN     string `xml:"coupon_refund_id_$n,omitempty"`  //退款代金券ID
	CouponRefundFeeN    string `xml:"coupon_refund_fee_$n,omitempty"` //单个代金券退款金额
	*/
	CouponRefunds      []WXPayCoupon
}
	
// 退款
func  Refund(appId,mchId,subAppid,subMchId,appSecret,transactionId,orderIdStr,refundNo,payFeeStr,refundFeeStr,crt,key string) (*RefundResponse,error){
	if len(subAppid) > 0 {
	    OrderQuery(appId,mchId,subAppid,subMchId,appSecret,"",orderIdStr)
	}else{
	    OrderQuery(appId,mchId,"","",appSecret,"",orderIdStr)
	}
	var (
	    req = new(RefundRequest)
	    rsp = new(RefundResponse)
	)
	cert, err := tls.X509KeyPair([]byte(crt), []byte(key))
	if err != nil {
		return rsp, err
	}
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
	client := core.GetWxPayClient(appId,mchId,appSecret,tlsConfig)
	if len(subAppid) > 0 {
	   req.SubAppid = subAppid
	}
	if len(subMchId) > 0 {
	   req.SubMchId = subMchId
	}
	if transactionId == "" && orderIdStr == "" {
	   return rsp, errors.New("Refund: at least of transation_id/out_trade_no required")
	}
	if refundNo == "" || payFeeStr == "" || refundFeeStr == ""{
	   return rsp, errors.New("Refund: out_refund_no/total_fee/refund_fee are required")
	}
	req.TransactionId = transactionId
	req.OutTradeNo =  orderIdStr      //商户订单号
	req.OutRefundNo = refundNo        //商户退款单号
	req.TotalFee = payFeeStr          // 单位是分
	req.RefundFee = refundFeeStr      // 单位是分
	rspMap, err := client.ExcuteMap(RefundUrl, req)
    if err != nil {
		return rsp, err
	}
	err = mapstruct.Map2Struct(rspMap, rsp, "xml")
	if err != nil {
		return rsp, err
	}
	if len(subAppid) > 0 {
		RefundQuery(appId,mchId,subAppid,subMchId,appSecret,"",orderIdStr,"","")
		
	}else{
	    RefundQuery(appId,mchId,"","",appSecret,"",orderIdStr,"","")
	}
	return rsp, nil
}

func  RefundOnCertFile(appId,mchId,subAppid,subMchId,appSecret,transactionId,orderIdStr,refundNo,
                         payFeeStr,refundFeeStr,crtFile,keyFile string) (*RefundResponse,error){
	
	if len(subAppid) > 0 {
	    OrderQuery(appId,mchId,subAppid,subMchId,appSecret,"",orderIdStr)
	}else{
	    OrderQuery(appId,mchId,"","",appSecret,"",orderIdStr)
	}
	var (
	    req = new(RefundRequest)
	    rsp = new(RefundResponse)
	)
	cert, err := tls.LoadX509KeyPair(crtFile, keyFile)
	if err != nil {
		beego.Debug("LoadX509KeyPair:", err.Error())
		return rsp, err
	}
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}
	client := core.GetWxPayClient(appId,mchId,appSecret,tlsConfig)
	if len(subAppid) > 0 {
	   req.SubAppid = subAppid
	}
	if len(subMchId) > 0 {
	   req.SubMchId = subMchId
	}
	if transactionId == "" && orderIdStr == "" {
	   return rsp, errors.New("Refund: at least of transation_id/out_trade_no required")
	}
	if refundNo == "" || payFeeStr == "" || refundFeeStr == ""{
	   return rsp, errors.New("Refund: out_refund_no/total_fee/refund_fee are required")
	}
	req.TransactionId = transactionId
	req.OutTradeNo =  orderIdStr      //商户订单号
	req.OutRefundNo = refundNo        //商户退款单号
	req.TotalFee = payFeeStr          // 单位是分
	req.RefundFee = refundFeeStr      // 单位是分
	rspMap, err := client.ExcuteMap(RefundUrl, req)
    if err != nil {
		return rsp, err
	}
	err = mapstruct.Map2Struct(rspMap, rsp, "xml")
	if err != nil {
		return rsp, err
	}
	if len(subAppid) > 0 {
	    RefundQuery(appId,mchId,subAppid,subMchId,appSecret,"",orderIdStr,"","")
	}else{
	    RefundQuery(appId,mchId,"","",appSecret,"",orderIdStr,"","")
	}
	return rsp, nil
}
